package _cache._redis;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 1、缓存穿透：key对应的数据在数据源并不存在，每次针对此key的请求从缓存获取不到，请求都会到数据源，从而可能压垮数据源。
 *      比如用一个不存在的用户id获取用户信息，不论缓存还是数据库都没有，若黑客利用此漏洞进行攻击可能压垮数据库。
 *     ========================================================================解决方案start===================================================================
 *      1、采用异步更新策略，无论key是否取到值，都直接返回。value值中维护一个缓存失效时间，缓存如果过期，异步起一个线程去读数据库，更新缓存。需要做缓存预热(项目启动前，先加载缓存)操作。
 *      2、提供一个能迅速判断请求是否有效的拦截机制，比如，利用布隆过滤器，内部维护一系列合法有效的key。迅速判断出，请求所携带的Key是否合法有效。如果不合法，则直接返回。
 *      3、对查询结果为空的情况也进行缓存，缓存时间设置短一点，或者该key对应的数据insert了之后清理缓存。
 *     ========================================================================解决方案end=====================================================================
 * 2、缓存击穿：第一次设置缓存或缓存失效的瞬间，如果存在大量并发，会绕过缓存判断直接访问数据库，压垮数据库。
 *     ========================================================================解决方案start===================================================================
 *      1、利用互斥锁，缓存失效的时候，先去获得锁，得到锁了，再去请求数据库。没得到锁，则休眠一段时间重试。
 *     ========================================================================解决方案end=====================================================================
 * 3、缓存雪崩：
 *      流量激增：比如异常流量、用户重试导致系统负载升高；
 *      缓存刷新：假设A为client端，B为Server端，假设A系统请求都流向B系统，请求超出了B系统的承载能力，就会造成B系统崩溃；
 *      程序有Bug：代码循环调用的逻辑问题，资源未释放引起的内存泄漏等问题；
 *      硬件故障：比如宕机，机房断电，光纤被挖断等。
 *      数据库严重瓶颈，比如：长事务、sql超时等。
 *      线程同步等待：系统间经常采用同步服务调用模式，核心服务和非核心服务共用一个线程池和消息队列。如果一个核心业务线程调用非核心线程，这个非核心线程交由第三方系统完成，当第三方系统本身出现问题，导致核心线程阻塞，一直处于等待状态，而进程间的调用是有超时限制的，最终这条线程将断掉，也可能引发雪崩；
 *     ========================================================================解决方案start===================================================================
 *      1、在缓存失效后，通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存，其他线程等待。
 *      2、不同的key，设置不同的过期时间，让缓存失效的时间点尽量均匀。
 *      3、做二级缓存，A1为原始缓存，A2为拷贝缓存，A1失效时，可以访问A2，A1缓存失效时间设置为短期，A2设置为长期
 *     ========================================================================解决方案end=====================================================================
 */
public class CacheBreakDown {

    public static void main(String[] args) {
        System.setProperty("spring.profiles.default", "test");
        ApplicationContext ac = new ClassPathXmlApplicationContext("xml/application*.xml");
        RedisTemplate redisTemplate = (RedisTemplate) ac.getBean("redisTemplate");
        boolean aaa = redisTemplate.hasKey("aaa");
        System.out.println(aaa);
    }
}
